﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Elentok.Common.Collections
{
  /// <summary>
  /// Defines a dictionary where each key points to a list of items
  /// </summary>
  /// <typeparam name="TKey">The key</typeparam>
  /// <typeparam name="TListItem">The type of item in each list</typeparam>
  public interface IDictionaryOfLists<TKey, TListItem>
  {
    /// <summary>
    /// Gets the value associated with the specified key (throws an exception if not found).
    /// </summary>
    /// <param name="key">The key of the value to get</param>
    /// <returns></returns>
    /// <exception cref="System.ArgumentNullException" />
    IList<TListItem> this[TKey key] { get; }

    /// <summary>
    /// Gets the value associated with the specified key (returns false if not found)
    /// </summary>
    /// <param name="key">The key of the value to get</param>
    /// <param name="items">If the key is found, this parameter will contain the value of the key.</param>
    /// <returns></returns>
    bool TryGetValue(TKey key, out IList<TListItem> items);

    /// <summary>
    /// Adds a new item to the dictionary
    /// </summary>
    /// <param name="key"></param>
    /// <param name="item"></param>
    void Add(TKey key, TListItem item);

    /// <summary>
    /// Gets a collection containing the keys of the dictionary
    /// </summary>
    IEnumerable<TKey> Keys { get; }
  }

  /// <summary>
  /// A dictionary where each key points to a list of items
  /// </summary>
  /// <typeparam name="TKey"></typeparam>
  /// <typeparam name="TListItem"></typeparam>
  public class DictionaryOfLists<TKey, TListItem>
    : IDictionaryOfLists<TKey, TListItem>
  {
    private Dictionary<TKey, IList<TListItem>> innerDictionary
      = new Dictionary<TKey, IList<TListItem>>();

    /// <summary>
    /// Gets the value associated with the specified key (throws an exception if not found).
    /// </summary>
    /// <param name="key">The key of the value to get</param>
    /// <returns></returns>
    /// <exception cref="System.ArgumentNullException" />
    public IList<TListItem> this[TKey key]
    {
      get 
      {
        return this.innerDictionary[key];
      }
    }

    /// <summary>
    /// Gets the value associated with the specified key (returns false if not found)
    /// </summary>
    /// <param name="key">The key of the value to get</param>
    /// <param name="items">If the key is found, this parameter will contain the value of the key.</param>
    /// <returns></returns>
    public bool TryGetValue(TKey key, out IList<TListItem> items)
    {
      return this.innerDictionary.TryGetValue(key, out items);
    }

    /// <summary>
    /// Adds a new item to the dictionary
    /// </summary>
    /// <param name="key"></param>
    /// <param name="item"></param>
    public void Add(TKey key, TListItem item)
    {
      IList<TListItem> list = null;
      if (!innerDictionary.TryGetValue(key, out list))
      {
        list = new List<TListItem>();
        innerDictionary.Add(key, list);
      }

      list.Add(item);
    }

    /// <summary>
    /// Gets a collection containing the keys of the dictionary
    /// </summary>
    public IEnumerable<TKey> Keys
    {
      get { return this.innerDictionary.Keys; }
    }
  }
}
